/*******************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.        */
/*                                                                 */
/*  NAME      = iconv2utf8.c                                       */
/*  NOTE      =                                                    */
/*  DATE      = 2014/10/01 by zhengxd                              */
/*******************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iconv.h>
#include <errno.h>

#include "frmem.h"
#include "frcomm.h"
#include "iconv2utf8.h"


int iconv_to_utf8(char *p_inbuffer
                  , unsigned int ui_inbuffer_size
                  , const char *p_from_charset
                  , char **pp_output_buffer
                  , unsigned int *p_ui_output_size)
{
    iconv_t fp = 0;
    size_t s_ret = 0;
    size_t s_out_left_size = 0;
    size_t s_out_size = 0;
    size_t s_in_left_size = 0;
    int i_count = 2;
    char *p_outbuf = NULL;
    char *p_output_tmp = NULL;
    char *p_input_tmp = NULL;

    /* 入力为空 */
    if (p_inbuffer == NULL || ui_inbuffer_size == 0)
    {
        return 0;
    }
    /* 申请一个字符集转换的描述符，从from charset到UTF-8 */
    fp = iconv_open("UTF-8", p_from_charset);
    /* 申请描述符失败 */
    if (fp == 0 || fp == (iconv_t)-1)
    {
        frdbg("iconv_open from[%s] failed, errno=[%d]\n", p_from_charset, errno);
        return 2;
    }

    /* 做iconv转换 */
    while (1)
    {
        /* 申请一块出力buffer用的内存 */
        s_out_size = ui_inbuffer_size * i_count + 1;
        p_outbuf = (char *)frmalloc(s_out_size);
        /* 申请内存出错 */
        if (p_outbuf == NULL)
        {
            frdbg("malloc failed\n");
            iconv_close(fp);
            return 2;
        }

        p_output_tmp = p_outbuf;
        p_input_tmp = p_inbuffer;
        s_in_left_size = ui_inbuffer_size;
        s_out_left_size = s_out_size;
        errno = 0;
        s_ret = iconv(fp, &p_input_tmp, &s_in_left_size, &p_output_tmp, &s_out_left_size);
        /* iconv出错 */
        if (s_ret != 0)
        {
            /* 出力buffer内存不足 */
            if (errno == E2BIG)
            {
                frdbg("Output memory is not enough\n");
                i_count++;
                frfree((void *)p_outbuf);
                p_outbuf = NULL;
                continue;
            }
            /* 有不可转换字符只取前面可转的那段 */
            else if (errno == EILSEQ)
            {
                frdbg("There has illegal byte sequence\n");
                p_outbuf[s_out_size - s_out_left_size] = '\0';
                *pp_output_buffer = p_outbuf;
                *p_ui_output_size = s_out_size - s_out_left_size;
                iconv_close(fp);
                return 1;
            }
            else
            {
                frfree((void *)p_outbuf);
                iconv_close(fp);
                return 2;
            }
        }
        else
        {
            break;
        }
    }

    *pp_output_buffer = p_outbuf;
    p_outbuf[s_out_size - s_out_left_size] = '\0';
    *p_ui_output_size = s_out_size - s_out_left_size;
    iconv_close(fp);
    return 0;
}
